home *** CD-ROM | disk | FTP | other *** search
/ The Atari Compendium / The Atari Compendium (Toad Computers) (1994).iso / files / prgtools / mint / utilit~1 / pstopls.zoo / ls.c next >
Encoding:
C/C++ Source or Header  |  1991-11-04  |  11.3 KB  |  517 lines

  1. /*
  2.  * "ls" for anything, including MiNT.
  3.  *
  4.  * By Allan Pratt, Atari Corp. (atari!apratt).
  5.  * Attribute suggestions and code from entropy@wookumz.ai.mit.edu 3/91.
  6.  *
  7.  * There's still one FIXME: "ls *.c" looks terrible, with each filename
  8.  * alone on a line, and double-spaced.  The top-level arguments should be
  9.  * gathered into a list, and that list sorted as a single "ls."  Then
  10.  * if any of those names are subdirectories, you get a double linefeed,
  11.  * then the name that generated the sublist, then the sublist.
  12.  */
  13.  
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <osbind.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19.  
  20. #ifdef __GNUC__
  21. /* minimal stuff */
  22.  
  23. #include <minimal.h>
  24. #include <stdarg.h>
  25.  
  26. int printf(const char *fmt,...)
  27. {
  28.     va_list args;
  29.     char buf[128];
  30.     va_start(args,fmt);
  31.     vsprintf(buf,fmt,args);
  32.     Cconws(buf);
  33.     return 0;
  34. }
  35.  
  36. #undef putchar
  37. #define putchar(c) Cconout(c)
  38. #endif
  39.  
  40. #define TRUE 1
  41. #define FALSE 0
  42.  
  43. #define DRV_CHAR ':'
  44. #define PATH_CHAR '\\'
  45.  
  46. /* is_root: TRUE for d: and d:\ */
  47. #define is_root(s) ((s)[1] == ':' && (!(s)[2] || ((s)[2] == '\\' && !(s)[3])))
  48.  
  49. /* is_dots: TRUE for . and .. */
  50. #define is_dots(s) (*(s) == '.' && (!(s)[1] || ((s)[1] == '.' && !(s)[2])))
  51.  
  52. extern char *syserr(long);
  53.  
  54. /* these all initialize to zero */
  55. struct _dta *dtas;
  56. int nfiles;
  57. int nalloc;
  58.  
  59. /* so do these */
  60. int lflag, fflag, aflag, rflag, tflag, dflag;
  61.  
  62. unsigned short too_long_ago;
  63.  
  64. char Monthname[] = "   JanFebMarAprMayJunJulAugSepOctNovDec";
  65.  
  66. int cmpname(const struct _dta *a, const struct _dta *b)
  67. {
  68.     return strcmp(a->dta_name,b->dta_name);
  69. }
  70.  
  71. int cmptrue(const struct _dta *a, const struct _dta *b)
  72. {
  73.     char *aname, *bname;
  74.  
  75.     aname = *(char **)a->dta_name;
  76.     bname = *(char **)b->dta_name;
  77.     return strcmp(aname,bname);
  78. }
  79.  
  80. int cmptime(const struct _dta *a, const struct _dta *b)
  81. {
  82.     unsigned long datime1, datime2;
  83.     datime1 = ((unsigned long)a->dta_date) << 16 |
  84.     (unsigned long)a->dta_time;
  85.     datime2 = ((unsigned long)b->dta_date) << 16 |
  86.     (unsigned long)b->dta_time;
  87.     if (datime1 > datime2) return -1;
  88.     else if (datime1 == datime2) return 0;
  89.     else return 1;
  90. }
  91.  
  92. void
  93. add_file(struct _dta *dta)
  94. {
  95.     if (dtas == NULL) {
  96.     dtas = malloc(10 * sizeof(struct _dta));
  97.     nalloc = 10;
  98.     nfiles = 0;
  99.     }
  100.     else if (nalloc == nfiles) {
  101.     nalloc += 10;
  102.     if ((dtas = realloc(dtas,nalloc * sizeof(struct _dta))) == NULL) {
  103.         printf("Out of memory\r\n");
  104.         Pterm(1);
  105.     }
  106.     }
  107.     dtas[nfiles] = *dta;
  108.     nfiles++;
  109. }
  110.  
  111. void
  112. add_named_file(struct _dta *dta, const char *truename)
  113. {
  114.     if (dtas == NULL) {
  115.     dtas = malloc(10 * sizeof(struct _dta));
  116.     nalloc = 10;
  117.     nfiles = 0;
  118.     }
  119.     else if (nalloc == nfiles) {
  120.     nalloc += 10;
  121.     if ((dtas = realloc(dtas,nalloc * sizeof(struct _dta))) == NULL) {
  122.         printf("Out of memory\r\n");
  123.         Pterm(1);
  124.     }
  125.     }
  126.     *(const char **)dta->dta_name = truename;
  127.     dtas[nfiles] = *dta;
  128.     nfiles++;
  129. }
  130.  
  131. void
  132. downcase(char *s)
  133. {
  134.     while (*s) {
  135.     if (isupper(*s)) *s = tolower(*s);
  136.     s++;
  137.     }
  138. }
  139.  
  140. /* GTP added for New Desktop -- GEM Takes Parameters */
  141.  
  142. char *suffixes[] = { ".ttp", ".prg", ".tos", ".app", ".gtp" };
  143. #define NSUFFIXES (sizeof(suffixes) / sizeof(char *))
  144.  
  145. inline int
  146. isexec(char *s)
  147. {
  148.     int i;
  149.     for (i = NSUFFIXES; --i >= 0; ) {
  150.     if (strstr(s,suffixes[i])) return 1;
  151.     }
  152.     return 0;
  153. }
  154.  
  155. char *
  156. str_attrib(int att, int exec)
  157. {
  158.     static char str[9];
  159.  
  160.     strcpy(str, "-r------");
  161.  
  162.     if (att & 0x10)
  163.     str[0] = 'd';
  164.     if (!(att & 0x01))
  165.     str[2] = 'w';
  166.     if (exec)
  167.     str[3] = 'x';
  168.     if (att & 0x20)
  169.     str[4] = 'a';
  170.     if (att & 0x02)
  171.     str[5] = 'h';
  172.     if (att & 0x04)
  173.     str[6] = 's';
  174.     if (att & 0x08)
  175.     str[7] = 'v';
  176.     return (str);
  177. }
  178.  
  179. /*
  180.  * showlist: take the dtas array (size is nfiles), sort it based
  181.  * on tflag, and output based on lflag.  Then free the dtas array
  182.  * and reinitialize the globals controlling it.
  183.  *
  184.  * If the argument truenames is true, and you're sorting by name,
  185.  * the 'name' field is a string pointer, not a string.
  186.  */
  187.  
  188. void
  189. showlist(int truenames)
  190. {
  191.     int (*cmpfn)(const void *,const void *);
  192.     int i, j, k, nrows;
  193.     struct _dta *s;
  194.     int exec;
  195.     char last_char;
  196.     char *nameptr;
  197.  
  198.     /* I hate this messy cast... */
  199.     if (tflag) {
  200.     cmpfn = (int (*)(const void *,const void *))cmptime;
  201.     }
  202.     else if (truenames) {
  203.     cmpfn = (int (*)(const void *,const void *))cmptrue;
  204.     }
  205.     else {
  206.     cmpfn = (int (*)(const void *,const void *))cmpname;
  207.     }
  208.  
  209.     qsort(dtas,(size_t)nfiles,sizeof(struct _dta),cmpfn);
  210.  
  211.     if (lflag) {
  212.     for (i = 0, s = dtas; i < nfiles; s++, i++) {
  213.         nameptr = (truenames ? *(char **)s->dta_name : s->dta_name);
  214.         exec = isexec(nameptr);
  215.         if (!fflag) last_char = ' ';
  216.         else if (s->dta_attribute & 0x10) last_char = '\\';
  217.         else if (exec) last_char = '*';
  218.         else last_char = ' ';
  219.  
  220.         if (lflag > 1) {
  221. /*
  222.  *     drwxahsv aa --size-- yy/mm/dd hh:mm:ss name*
  223.  */
  224.         printf("%s %02x %8ld %02d/%02d/%02d %02d:%02d:%02d %s%c\r\n",
  225.             str_attrib(s->dta_attribute,exec),
  226.             s->dta_attribute,
  227.             s->dta_size,
  228.             (s->dta_date >> 9) + 80,
  229.             (s->dta_date >> 5) & 0xf,
  230.             (s->dta_date) & 0x1f,
  231.  
  232.             (s->dta_time >> 11),
  233.             (s->dta_time >> 5) & 0x3f,
  234.             (s->dta_time & 0x1f),
  235.             nameptr,
  236.             last_char);
  237.         }
  238.         else {
  239.  
  240. /*
  241.  *     drwxahsv --size-- Mon dy hh:mm name*
  242.  *  or drwxahsv --size-- Mon dy  year name*   if date is >~8mos old
  243.  */
  244.  
  245.         if (s->dta_date >= too_long_ago) {
  246.             /* recent form, includes in the future! */
  247.  
  248.             printf("%s %8ld %.3s %2d %02d:%02d %s%c\r\n",
  249.             str_attrib(s->dta_attribute,exec),
  250.             s->dta_size,
  251.             &Monthname[((s->dta_date >> 5) & 0xf)*3],
  252.             (s->dta_date) & 0x1f,
  253.  
  254.             (s->dta_time >> 11),
  255.             (s->dta_time >> 5) & 0x3f,
  256.  
  257.             nameptr,
  258.             last_char);
  259.         }
  260.         else {
  261.             /* old form */
  262.             printf("%s %8ld %.3s %2d  %4d %s%c\r\n",
  263.             str_attrib(s->dta_attribute,exec),
  264.             s->dta_size,
  265.             &Monthname[((s->dta_date >> 5) & 0xf)*3],
  266.             (s->dta_date) & 0x1f,
  267.             (s->dta_date >> 9) + 1980,
  268.  
  269.             nameptr,
  270.             last_char);
  271.         }
  272.             }
  273.     }
  274.     }
  275.     else {
  276.  
  277. #define NCOLS 5
  278.  
  279.     /* not lflag: output in 5-column format */
  280.     nrows = (nfiles + (NCOLS-1)) / NCOLS;
  281.     for (i = 0; i < nrows; i++) {
  282.         s = &dtas[i];
  283.         for (j = 0; j < NCOLS; j++, s += nrows) {
  284.         if (s >= &dtas[nfiles]) {
  285.             printf("\r\n");
  286.             break;
  287.         }
  288.  
  289.         nameptr = (truenames ? *(char **)s->dta_name : s->dta_name);
  290.         printf("%s",nameptr);
  291.         k = strlen(nameptr);
  292.         if (fflag) {
  293.             if (s->dta_attribute & 0x10) {
  294.             putchar('\\');
  295.             k++;
  296.             }
  297.             else if (isexec(nameptr)) {
  298.             putchar('*');
  299.             k++;
  300.             }
  301.         }
  302.         /* don't output tab(s) after the last name on a line */
  303.         if (j < (NCOLS-1)) {
  304.             if (k<8) putchar('\t');
  305.             putchar('\t');
  306.         }
  307.         else printf("\r\n");
  308.         }
  309.     }
  310.     }
  311.  
  312.     if (dtas) {
  313.     free(dtas);
  314.     dtas = NULL;
  315.     nalloc = 0;
  316.     nfiles = 0;
  317.     }
  318. }
  319.  
  320. void
  321. do_dir(const char *name) {
  322.     char buf[128];        /* requested path ends up here */
  323.     char *temp;
  324.     struct _dta *odta = (struct _dta *)Fgetdta();
  325.     struct _dta dta;
  326.     char *p;
  327.     int n;
  328.     long e;
  329.  
  330.     strcpy(buf,name);
  331.     temp = buf;
  332.     while (*temp) temp++;
  333.  
  334.     /*
  335.      * Find the file.  If it turns out to be a directory, add "\*.*" to it.
  336.      */
  337.  
  338.     (void)Fsetdta(&dta);
  339.  
  340.     if ((e = Fsfirst(buf,-1)) < 0) {
  341.     /* failed.  Might be d: or d:\ */
  342.     if (is_root(buf)) {
  343.         /* OK, no -d and it's d: or d:\ -- tack on *.* and try again */
  344.         strcpy(temp,"*.*");
  345.     }
  346.     else {
  347.         printf("%s: %s\r\n",buf,syserr(e));
  348.         goto reallydone;
  349.     }
  350.     }
  351.     else {
  352.     /* found the file: is it a directory? */
  353.     if (dta.dta_attribute & 0x10) {
  354.         /* directory: add \*.* to it */
  355.         /* \\ below should be PATH_CHAR */
  356.         strcpy(temp,"\\*.*");
  357.         temp++;
  358.     }
  359.     else {
  360.         /* no wildcards, file exists, not a directory: unique */
  361.         downcase(dta.dta_name);
  362.         add_file(&dta);
  363.         goto gotfiles;
  364.     }
  365.     }
  366.  
  367.     /* do the Fsfirst again because buf may have changed */
  368.     if ((e = Fsfirst(buf,-1)) < 0) {
  369.     printf("%s: %s\r\n",buf,syserr(e));
  370.     goto reallydone;
  371.     }
  372.  
  373.     do {
  374.     /* add the file to the list of files */
  375.     /* add all files if aflag, else skip those with leading dots */
  376.     if (aflag || *(dta.dta_name) != '.') {
  377.         downcase(dta.dta_name);
  378.         add_file(&dta);
  379.     }
  380.     } while (Fsnext() == 0);
  381.  
  382.     if (nfiles == 0) {
  383.     printf("no files\r\n");
  384.     goto reallydone;
  385.     }
  386.  
  387. gotfiles:
  388.     showlist(0);    /* uses globals dtas, nfiles, tflag, lflag, etc. */
  389.  
  390.     if (rflag) {
  391.     /* Do another Fsfirst/Fsnext pass for directories. */
  392.     /* Remember, buf has the Fsfirst target. */
  393.     /* Set temp just past the last PATH_CHAR or DIR_CHAR. */
  394.  
  395.     if ((temp = strrchr(buf,PATH_CHAR)) == NULL) temp = buf;
  396.     else temp++;
  397.  
  398.     if ((p = strrchr(temp,DRV_CHAR)) != NULL) temp = p+1;
  399.  
  400.     if (Fsfirst(buf,-1) < 0) goto reallydone;
  401.     do {
  402.         if ((dta.dta_attribute & 0x10) &&
  403.         (!is_dots(dta.dta_name))) {
  404.             strcpy(temp,dta.dta_name);
  405.             downcase(buf);
  406.             printf("\r\n%s:\r\n",buf);
  407.             do_dir(buf);
  408.             }
  409.     } while (!Fsnext());
  410.     }
  411.             
  412. reallydone:
  413.     (void)Fsetdta(odta);
  414. }
  415.  
  416. void
  417. top_level(const char **names)
  418. {
  419.     long e;
  420.     struct _dta dta;
  421.  
  422.     Fsetdta(&dta);
  423.  
  424.     /* call add_file for each name if Fsfirst on it succeeds */
  425.     while (*names) {
  426.     if (is_root(*names)) {
  427.         /* pretend to succeed on d: and d:\ but do nothing */
  428.     }
  429.     else if ((e = Fsfirst(*names,-1)) < 0) {
  430.         printf("%s: %s\r\n",*names,syserr(e));
  431.         *names = NULL;
  432.     }
  433.     else {
  434.         add_named_file(&dta,*names);
  435.         if (!(dta.dta_attribute & 0x10)) *names = NULL;
  436.     }
  437.     ++names;
  438.     }
  439.     showlist(1);
  440. }
  441.  
  442. int
  443. main(int argc,char *argv[])
  444. {
  445.     char *p;
  446.     int many;
  447.     char *dot = ".";
  448.  
  449.     --argc, ++argv;
  450.     while (*argv && **argv == '-') {
  451.     p = &argv[0][1];
  452.     while (*p) {
  453.         switch (*p) {
  454.         case 'l': lflag++; break;   /* more is better */
  455.         case 'F': fflag = 1; break;
  456.         case 'a': aflag = 1; break;
  457.         case 'R': rflag = 1; break;
  458.         case 't': tflag = 1; break;
  459.         case 'd': dflag = 1; break;
  460.         default:
  461.          printf("Unknown option: %c\r\n",*p);
  462.          printf("Usage: ls [-adFlRt] [files ...]\r\n");
  463.          printf("A second -l gives time and date in absolute form\r\n");
  464.          exit(1);
  465.         }
  466.         p++;
  467.     }
  468.     argc--, argv++;
  469.     }
  470.  
  471.     if (!argc) {
  472.     argc = 1;
  473.     argv = ˙
  474.     }
  475.  
  476.     /* if lflag, figure out when "too long ago" is */
  477.     if (lflag) {
  478.     unsigned short now = Tgetdate();
  479.     unsigned short thisyear = (now >> 9);
  480.     unsigned short thismonth = (now >> 5) & 0xf;
  481.     if (thismonth >= 8) {
  482.         thismonth -= 8;
  483.     }
  484.     else {
  485.         thismonth += 4;
  486.         thisyear -= 1;
  487.     }
  488.     too_long_ago = (thisyear << 9) | (thismonth << 5);
  489.     }
  490.  
  491.     /*
  492.      * Do a top-level 'ls' on all the args, if you gave more than one.
  493.      * top_level zeros those argv ptrs which refer to files, not directories.
  494.      *
  495.      * Do this also if dflag, and in addition don't call do_dir.
  496.      */
  497.  
  498.     if (argc > 1 || dflag) {
  499.     many = 1;
  500.     top_level((char **)argv);
  501.     if (dflag) exit(0);
  502.     }
  503.     else many = 0;
  504.     
  505.     while (argc) {
  506.         if (*argv) {
  507.         if (many) {
  508.         printf("\r\n%s:\r\n",*argv);
  509.         }
  510.         do_dir(*argv);
  511.     }
  512.     argv++, argc--;
  513.     }
  514.     exit(0);
  515. }
  516.  
  517.